	PAGESIZE	74
	PAGEWIDTH	132
;
; A BIOS FOR CPM-86 (v1.X) USING A HARD DISK, 2 FLOPPY DISKS & A RAMDISK
;
; IT IS SETUP AT THE MOMENT FOR ONE MINISCRIBE 10MG BYTE HARD DISK DRIVE &
; ONLY 2 8" DRIVES CONTROLLED BY THE 1791 CHIP. THIS BIOS IS VERY HARDWARE
; DEPENDENT AND WOULD REQUIRE SOME REWORKING FOR OTHERE S-100 BOARDS.
; THE S100 BOARDS ARE THE VERSAFLOPPY II, THE XCOMP HARD DISK CONTROLLERS.
; THE BIOS HAS SOME LINKS TO OTHER HOMEBREW BOARDS I USE. THESE ARE AN IO
; MAPPED 1MG BYTE MEMORY DISK, A SPEECH SYNTHESIS BOARD, AND A KEYBOARD WITH
; TYPE-AHEAD,TRANSLATION ETC. THESE NEED NOT CONCERN YOU SINCE THEY ARE ONLY
; INITILIZED IN THE BIOS.
;
;
;	AUTHOR:	JOHN J. MONAHAN		(201)583-1548		7/1/82
;	MODIFIED FOR RAMDISK 					7/5/83
;	MODIFIED FOR SPEECH SYNTHESIS				10/29/83
;	MODIFIED FOR SD 8024 BOARD / KEYBOARD Z80 CONTROLLER	1/1/84
;
;-------- PORTS USED IN IO DRIVERS FOR CONSOLE ETC.------------------
;
IOBYTE	EQU	0FFH		;IOBYTE (SEE BELOW)
SDSTAT	EQU	0H
SDDATA	EQU	1H
KEYSTAT	EQU	0H		;SEPERATE PORT TO SEE IF ANYTHING AT KEYBOARD
KEYIN	EQU	01H
resetkey equ	0f8h		;inputting from this port causes an NMI on my
;				;z80 keyboard board to force the CPM keyboard
;				
CENTOUT	EQU	5H		;CENTRONICS PRINTER PORT
CENTSTAT EQU	5H
CENTSTROBE EQU	4H
;
TALKSTAT EQU	0B0H		;REQ FOR SPEECH SYNTHESIS
TALKOUT	EQU	0B1H
;
; MISC. EQUATES FOR RAMDISK
;
CMDDLY	EQU	0FFFFH
MAXTRK	EQU	2		;RETURN MAXIMUM TRACK # OF MEMORY DISK
RDSECTOR EQU	0
WRTSECTOR EQU	1
CTRLPORT EQU	0B6H		;WAS 7
DATAPORT EQU	0B8H		;WAS 6
;
;------- HARD DISK PARAMETERS --------------------------------------
;
MAXSEC	EQU	32			;SECTORS PER TRACK ON HARD DISK
MAXCYL	EQU	500			;NUMBER OF CYLINDERS/HEAD
LZONE	EQU	656
BLKSIZ	EQU	2048			;BYTES PER BLOCK FOR HARD DISK
CPMSPT	EQU	2*MAXSEC		;CPM SECTORS PER TRACK FOR HARD DISK
HSKCMD	EQU	3			;SEEK CMD FOR HARD DISK CONTROLLER
SKOUT	EQU	1
NOPC	EQU	40H			;NO PRE-COMPENSATION
LOWRT	EQU	80H			;LOW WRITE CURRENT
READY	EQU	1			;HARD DISK DRIVE READY
WRTFLT	EQU	2			;HARD DISK WRITE FAULT
TK00	EQU	4			;HARD DISK TRACK ZERO
RAWINDX	EQU	20H			;HARD DISK RAW INDEX
BANK0	EQU	0			;BANK 0 SELECT ON XCOMP CONTROLLER
BANK1	EQU	1			;BANK 1 SELECT
DBENB	EQU	2			;DATA BUFFER ENABLE
CBENB	EQU	4			;COMPARE BUFFER ENABLE
START	EQU	8			;START COMMAND FOR XCOMP CONTROLLER
VSA	EQU	8			;SEEK VERIFY START ADDRESS
VCA	EQU	1BH			;SEEK VERIFY COMPARE ADDRESS
CBASE	EQU	70H			;BASE ADR OF THE XCOMP CONT PORTS
DRCSR	EQU	CBASE			;DRIVE COMMAND/STATUS
EXTCMD	EQU	CBASE+1			;EXTENDED COMMNAND REGISTER
LOSC	EQU	CBASE+2			;SEEK COUNT, LSB
HISC	EQU	CBASE+3			;SEEK COUNT, MSB
CTCSR	EQU	CBASE+4			;CONTROLLER COMMAND/STATUS
CTBFR	EQU	CBASE+5			;CONTROLLER BUFFER ADDRESS
CTDP	EQU	CBASE+6			;CONTROLLER DATA PORT
;
;------	VERSAFLOPPY II DISK PARAMETERS ---------------------------------
;
X	EQU	60H			;BASE ADDRESS OF PORTS FOR 1791
RSET	EQU	X+0			;CONTROLLER RESET ADDRESS
SELECT	EQU	X+3			;DRIVE SELECT PORT
STATUS	EQU	X+4			;STATUS PORT
TRACK	EQU	X+5			;TRACK PORT
SECTOR	EQU	X+6			;SECTOR PORT
DATA	EQU	X+7			;DATA PORT
CMD	EQU	X+4			;COMMAND PORT
RDACMD	EQU	0C0H			;READ ADDRESS CODE
RDCMD	EQU	088H			;READ SECTOR CODE
WRCMD	EQU	0A8H			;WRITE SECTOR CODE
WRTCMD	EQU	0F4H			;WRITE TRACK CODE
RSCMD	EQU	009H			;RESTORE COMMAND
SKNCMD	EQU	019H			;SEEK NO VERIFY
SKCMD	EQU	1DH			;SEEK WITH VERIFY
STDSDT	EQU	26			;STANDARD 8" 26 SECTORS/TRACK
STDDDT	EQU	50			;STANDARD DD 8" 50 SECTORS/TRACK
NBYTES	EQU	128			;BYTES/SECTOR 
NTRKS	EQU	77			;TRACKS/DISK
;
;
;   ASCII CHARACTERS
;
CR	EQU	0DH			;CARRIAGE RETURN
LF	EQU	0AH			;LINE FEED
BELL	EQU	7			;DING
;
;
	CSEG
	ORG	0H
CCP:
;
;============================================================================
;									     
;	THE CPM-86 CCP AND BDOS WILL GO HERE ( ABSOLUTE 500H TO 25FFH)
;
;	{I leave 100h bytes for an 8089 below cpm for my system. so the
;	org value is 2500h.  You may want to use 2400h as DR does}
;
;	NOTE WITH THIS 8089 VERSION I HAVE EVERYTHING 100H HIGHER
;	THAN EVERYTHING IN THE DIGITAL RESEARCH MANUAL.
;	SO THE CCP AND BDOS WILL BE FROM 500H TO 25FFH AND 8089
;	TABLE AT 400H TO 500H.
;									     
;============================================================================
;
	ORG	2500H			;NOW THE START OF THE CUSTOM BIOS
					;NOTE ACTUAL ADDRESS IS 2A00H BECAUSE
					;OF [CS] OFFSET
;	---JUMP TABLE---
;
CPMINIT:JMP	INIT			;  0 - COLD BOOT
WBX:	JMP	WBOOT			;  1 - WARM BOOT
	JMP	CSTS			;  2 - CONSOLE STATUS REQUEST
ZCI:	JMP	CI			;  3 - CONSOLE INPUT
ZCO:	JMP	CO			;  4 - CONSOLE OUTPUT
ZLO:	JMP	LO			;  5 - LIST OUTPUT
	JMP	POO			;  6 - PUNCH OUTPUT
	JMP	RI			;  7 - READER INPUT
	JMP	HOME			;  8 - TRACK ZERO SEEK
	JMP	SETDR			;  9 - SET DRIVE #
	JMP	SETTK			; 10 - SET TRACK ADR
	JMP	SETSEC			; 11 - SET SECTOR ADR
	JMP	SETDMA			; 12 - SET BUFFER ADDRESS
	JMP	READ			; 13 - READ A SECTOR
	JMP	WRITE			; 14 - WRITE A SECTOR
ZLISTS:	JMP	LSTAT			; 15 - LIST OUTPUT READY TEST
	JMP	SXR			; 16 - SECTOR XLATE ROUTINE
	JMP	SETDMAB			; 17 - SET SEG BASE FOR BUFFER
	JMP	GETSEGT			; 18 - GET MEM DESC TABLE OFFSET
	JMP	GETIOBF			; 19 - RETURN IO BYTE
	JMP	SETIOBF			; 20 - SET IO BYTE
;
;		=====================
;		** CBIOS FUNCTIONS **
;		=====================
;		  ---COLD BOOT---
;
;
INIT:	MOV	AX,CS
	MOV	SS,AX
	MOV	DS,AX
	MOV	ES,AX
	MOV	SP, OFFSET STKBASE		;USE A LOCAL STACK
	CLD
	PUSH	DS
	MOV	AX,0
	MOV	DS,AX
	MOV	ES,AX
	MOV	INT0_OFFSET, OFFSET INT_TRAP	;INT0 TO ADDRESS TRAP ROUTINE
	MOV	INT0_SEGMENT, CS
	MOV	DI,4
	MOV	SI,0
	MOV	CX,510				;TRAP VECTOR TO ALL 256 INTS
   REP	MOVS 	AX,AX
	MOV	BDOS_OFFSET, 0B06H		;BDOS OFFSET TO PROPER INT0
	MOV	BDOS_SEGMENT,CS
	MOV	INT0_OFFSET, OFFSET INT0_TRAP
	MOV	INT4_OFFSET, OFFSET INT4_TRAP
	POP	DS
;		
	CALL	XTKZ			;BRING HEADS OF HDISK TO TRK 0
;
	MOV	BX,OFFSET FLAGS		;CLEAR RAM STORAGE AREA
	MOV	CH, FLGSIZ
	XOR	AL,AL
INIT1:	MOV	BYTE PTR [BX],AL	;CLEAR FLAGS & VARIABLES
	INC	BX
	DEC	CH
	JNZ	INIT1
	MOV	BYTE PTR IOBYT, AL	;CLEAR IOBYTE
	DEC	AL			;0FFH IN AL
	MOV	BYTE PTR ADRIVE, AL	;COME ON WITH B: & C: DENSITY UNKNOWN
	MOV	BYTE PTR BDRIVE, AL
	OUT	CENTSTROBE,AL		;CLEAR PRINTER PORT JUST IN CASE
	IN	AL,DATAPORT		;CLEAR GARBAGE FROM PARALLEL PORT FOR
					;MDISK
	in	al,resetkey		;to insure cpm table in z80board
	MOV	WORD PTR DMASEG, CS	;SET DEFAULT SEGMENT DMA TO HERE
	MOV	BX,OFFSET SIGNON
	CALL	PMSG
	MOV	BX,OFFSET SPEAKON
	CALL	SMSG
	MOV	CL,0			;DEFAULT TO DRIVE A:
	JMP	CCP
;
;	---WARM BOOT---
;
WBOOT:	in	al,resetkey		;to insure cpm table in z80board
	XOR	AL,AL
	DEC	AL
	MOV	BYTE PTR ADRIVE,AL	;PUT 0FFH IN FLOPPY A & B STORE
	MOV	BYTE PTR BDRIVE,AL
	JMP	CCP + 6			;GOTO CPM
;	
;
;	--- INT TRAP ROUTINES ---
INT0_TRAP: CLI	
	MOV	BX,OFFSET INT0_TRP	;DIVIDE TRAP HALT
	JMPS	INT_HALT

INT4_TRAP: CLI
	MOV	BX,OFFSET INT4_TRP	;OVERFLOW TRAP HALT
	JMPS	INT_HALT

INT_TRAP: CLI
	MOV	BX,OFFSET INT_TRP	;INTERRUPT TRAP HALT

INT_HALT:MOV	AX,CS
	MOV	DS,AX
	CALL	PMSG
	POP	BX			;GET SEGMENT
	POP	AX			;PRINT SEGMENT
	PUSH	BX
	CALL	PHEX
	MOV	CL,':'
	CALL	ZCO			;PRINT OFFSET
	POP	AX
	CALL	PHEX
	HLT				;HOLD EVERYTHING
;
PHEX:	PUSH	AX
	MOV	AL,AH
	CALL	PHXB
	POP	AX
PHXB:	PUSH	AX
	MOV	CL,4
	SHR	AL,CL
	CALL	PHXD
	POP	AX
	AND	AL,0FH			;ISOLATE LOWER NIBBLE
PHXD:	ADD	AL,90H			;DISPLAY A NIBBLE
	DAA
	ADC	AL,40H
	DAA
	MOV	CL,AL
	CALL	ZCO
	RET
;
GETIOBF: MOV	AL,IOBYT
	RET
;
SETIOBF: MOV	IOBYT,CL
	RET
;

PMSG:	MOV	AL,[BX]			;PRINT A STRING
	TEST	AL,AL
	JZ	RETURN
	MOV	CL,AL
	CALL	ZCO
	INC	BX
	CALL	PMSG
RETURN:	RET


;	---SECTOR TRANSLATE ROUTINE---
;
SXR: 	TEST	DX,DX
	JNZ	SXR1			;IF Z THEN NO TRANSLATION IS REQ
	MOV	BX,CX
	RET
;
SXR1:	MOV	BX,CX			;TRANS SEC [CX] USING TABLE AT [DX]
	ADD	BX,DX			;WILL HAVE NO TRANSLATION FOR MDISK
	MOV	BL,[BX]
	RET
;
;	---HOME---
;
HOME:	MOV	AL,BYTE PTR RRDSK	;DRIVE #
	CMP	AL,1			;SET AT THE MOMENT FOR ONE HARD DISK
	JNB	HOMEX
	JMP	XSTZ			;JIF REZERO HARD DISK
HOMEX:	MOV	CX,0			;RETURN ZERO JUST IN CASE
	JMP	SETTK
;
;	---READ---
;
READ:	MOV	AL,BYTE PTR RRDSK	;DRIVE #
	CMP	AL,1
	JNB	LAB13	
	JMP	HDREAD			;JIF READ FROM H/D
LAB13:	CMP	AL,3
	JNB	LAB14	
	JMP	FREAD			;JIF READ FROM F/D
LAB14:	CMP	AL,12			;CHECK IF MDISK
	JNZ	SELERR			;IF M: THEN MDISK
	JMP	MREAD
;
SELERR:	XOR	AL,AL
	DEC	AL
	RET				;RETURN WITH NZ FLAG FOR ERROR
;
;	---WRITE---
;
WRITE:	MOV	AL,BYTE PTR RRDSK	;DRIVE #
	CMP	AL,1
	JNB	LAB15	
	JMP	HDWRT			;JIF WRITE ONTO H/D
LAB15:	CMP	AL,3
	JNB	LAB16	
	JMP	FWRITE			;JIF WRITE ONTO F/D
LAB16:	CMP	AL,12			;CHECK IF MDISK
	JNZ	SELERR			;IF F: THEM MDISK
	JMP	MWRITE
;
;	---SET DRIVE NUMBER---
;
SETDR:	MOV	AL,CL			;A = NEW DRIVE #
	MOV	BYTE PTR RRDSK,AL	;  SAVE IT
	MOV	BX,0
	CMP	AL,12			;TEST FOR MDISK
	JE	MDSELDSK
	CMP	AL,3
	JNAE	LAB17			;NOT M:, A:, B:, OR C: SO ERROR
	RET				;RIF INVALID DRIVE # WITH [BX]=0
;
LAB17:	CMP	AL,0			;IF NOT 0 IE. [A:] MUST BE FLOPPYS
	JE	LAB18	
	CALL	FSELDSK			;RET WITH LOGICAL DRIVE OFFSET IN [A]
LAB18:	MOV	BL,AL			;B: OR C: (OR FOR DD D: OR E:)
	MOV	BH,0			
	MOV	CL,4
	SHL	BX,CL			;TIMES 16 
	ADD	BX,OFFSET DPHDR
	RET
;
; 
MDSELDSK:
	TEST	DL,01
	JZ	GETMDSK			;UPDATE DPB
	MOV	BX,OFFSET DPE12		;HEADER FOR DISK WILL ALWAYS BE HERE
	RET
;
GETMDSK:MOV	CL,MAXTRK		;NEED MAXIMUM TRACK # FROM RAMDISK
	CALL	MRDCMD			;SO SEND COMMAND TO RAMDISK
	JNB	MDINIT1			;SKIP NEXT IF COMMAND SENT OK
MDINIT0:MOV	BX,0			;THIS WILL FLAG BDOS
	RET
;
MDINIT1:CALL	RDREAD			;WAIT FOR MAXIMUM TRACK BYTE
	CMP	AL,-1			;IF TRACK =-1 THEN NO MDISK AVAILABLE
	JZ	MDINIT0
	INC	AL			;PUT TRACK INTO RANGE 1 - N
	MOV	BL,AL			;MAKE TRACK DOUBLE PRECISION IN [HL]
	MOV	BH,0
	MOV	DX,BX			;KEEP COPY IN [DX]
	MOV	CL,5
	SHL	BX,CL			;X32
	SUB	BX,DX			;X31
	SUB	BX,DX			;X30 (THIS IS # 2K BLOCKS / TRACK)
	MOV	AL,BH			;GET HI BYTE OF DSM TO [A]
	OR	AL,AL			;IS IT > 0 ?
	MOV	AL,0			;ASSUME >= 256 BLOCKS
	JNZ	MDINIT2
	MOV	AL,1			;ELSE EXM MUST = 1
MDINIT2:
	MOV	BYTE PTR DPB_EXM,AL		;STORE EXM BYTE INTO DPB
	DEC	BX			;# 2K BLOCKS - 1
	MOV	WORD PTR DPB_DSM,BX	;UPDATE DPB DSM FIELD
	MOV	BX,OFFSET DPE12
	RET
;
;	---SET SECTOR ADR---
;
SETSEC:	MOV	WORD PTR RRSEC,CX	;SAVE SECTOR ADR (NEED CX BECAUSE THE
					;MDISK HAS UP TO 480 SECTORS/"TRACK"
					;SET REAL SEC ADR FOR THE HARD DISK
	AND	CL,0FEH			;DRIVER.
	ROR	CL,1			;THERE ARE 2 CPM SECTORS PER H/D SECT
	MOV	BYTE PTR RSA,CL		;SAVE REAL SECTOR ADR 
	RET
;	
;	---SET TRACK ADDRESS---
;
SETTK:	MOV	WORD PTR RRTRK,CX	;SAVE TRACK ADR
	RET
;
;	---SET DMA ADDRESS---
;
SETDMA:	MOV	WORD PTR DMADR,CX	;SAVE DMA ADR
	RET
;
;	---- SET DMA SEGMENT ---
;
SETDMAB:MOV	WORD PTR DMASEG,CX
	RET
;
;	---- GET MEMORY MAP ---
GETSEGT:MOV	BX, OFFSET SEG_TABLE
	RET
;
;	======================================
;	** HARD DISK BLOCK/DEBLOCK ROUTINES **
;	======================================
;
;	---HARD DISK READ---
;
HDREAD:	XOR	AL,AL
	MOV	BYTE PTR ERFLG,AL	;CLEAR THE ERROR FLAG
	MOV	AL,BYTE PTR FLAGS	;SET READ OPERATION FLAG
	OR	AL,00000001B		;SET	0,A
	MOV	BYTE PTR FLAGS,AL
	AND	AL,00000100B		;BIT 	2,A
	JZ	LAB19	
	CALL	XWRT			;YES, WRITE DATA BEFORE READ
LAB19:	MOV	AL,BYTE PTR FLAGS
	AND	AL,11111011B		;RES	2,A	RESET WIP FLAG
	MOV	BYTE PTR FLAGS,AL
	CALL	TSTHST			;HOST = REQ ?
	JNZ	HDRD1			;NO, READ A BLOCK
	MOV	AL,BYTE PTR FLAGS
	AND	AL,02H			;PRIOR BLOCK READ ?
	JNZ	HDRD2			;YES, JUST EXTRACT DATA FROM BFR
HDRD1:	CALL	SETHST			;MAKE HOST=REQ
	CALL	XREAD			;READ A BLOCK
HDRD2:	CALL	GETDMA			;GET DMA ADR, SET POINTERS
	PUSH	ES
	MOV	ES, WORD PTR DMASEG 	;GET CORRECT SEGMENT
	MOV	DI,BX
	CLD				;SET DIRECTION FLAG
	IN	AL,CTDP			;PRIME DATA INPUT
HDRD3:	IN	AL,CTDP			;<<<<<<<<<<<<<< INPUT 128 BYTES >>>>>
	STOS	AL			;NOTE POINTER IS [ES] & [DI]
	LOOP	HDRD3			;WILL HAVE AUTO INC OF [CX] & [DI]
	POP	ES	
	MOV	AL,BYTE PTR FLAGS
	OR	AL,00000010B		;SET  1,A  SET READ-IN-PROGRESS FLAG
	MOV	BYTE PTR FLAGS,AL
	MOV	AL,BYTE PTR ERFLG	;ERROR FLAG
	RET
;	
;	---HARD DISK WRITE---
;
;
HDWRT:	XOR	AL,AL
	MOV	BYTE PTR ERFLG,AL	;CLEAR THE ERROR FLAG
	MOV	AL,BYTE PTR FLAGS
	AND	AL,11111101B		;RES  1,A CLEAR READ-IN-PROGRESS FLAG
	MOV	BYTE PTR FLAGS,AL
	MOV	AL,CL			;AL= 0 NORMAL = 1 DIR = 2 UNALLOCATED
	DEC	AL
	JNZ	LAB20	
	JMP	WDIR			;DO DIRECTORY WRITE
LAB20:	JNS	WUN
	JMP	WNORM			;DO NORMAL WRITE
;
;   UNALLOCATED WRITE
;
WUN:	MOV	AL,BYTE PTR FLAGS
	AND	AL,00000100B		;BIT    2,A     WRITE IN PROGRESS ?
	JZ	LAB21	
	CALL	XWRT			;YES, WRITE DATA IN BFR
LAB21:	MOV	AL,BLKSIZ/128		;SET UNALLOC RECORD PARAMETERS
	MOV	BYTE PTR URCNT,AL	;SET UNALLOC RECORD COUNT
	MOV	BX,WORD PTR RRDSK
	MOV	WORD PTR URDSK,BX	;UPDATE DRIVE & SECTOR
	MOV	BX,WORD PTR RRTRK
	MOV	WORD PTR URTRK,BX	;UPDATE TRACK ADR
	CALL	SETHST			;SET HOST = REQ
	CALL	BUMP			;BUMP UNALC PARMS FOR NEXT PASS
					;XFER DATA TO CTLR BFR
WXFER:	MOV	AL,BYTE PTR FLAGS
	AND	AL,11111110B		;RES  0,A        CLEAR READ OPER FLAG
	MOV	BYTE PTR FLAGS,AL
	CALL	GETDMA			;GET DMA ADR, SET FOR WRITE
	PUSH	DS
	MOV	DS, WORD PTR DMASEG	;GET CORRECT SEGMENT
	CLD
	MOV	SI,BX
WXFER1:	LODS	AL			;>>>>>>>>>OUTPUT 128 BYTES<<<<<<<<<<<
	OUT	CTDP,AL			;POINTER WILL BE [DS] AND [SI]
	LOOP	WXFER1
	POP	DS			;RESTORE [DS]
	MOV	AL,BYTE PTR FLAGS
	OR	AL,00000100B		;SET  2,A  SET WRITE-IN-PROGRESS FLAG
	MOV	BYTE PTR FLAGS,AL
	MOV	AL,BYTE PTR ERFLG	;ERROR FLAG
	RET
;
;   NORMAL WRITE
;
WNORM:	MOV	AL,BYTE PTR URCNT	;UNALC RECORD COUNT
	OR	AL,AL
	JZ	WALC			;JIF DO ALLOC WRITE
	MOV	BX,(OFFSET URTRK)
	CALL	DSKCMP			;UNALC DSK/TRK = REQ DSK/TRK ?
	JNZ	WALC			;NO, DO ALLOC WRITE
	MOV	AL,BYTE PTR RRSEC
	CMP	AL,BYTE PTR [BX]	;UNALC SECT = REQ SECT ?
	JNZ	WALC			;NO, DO ALLOC WRITE
	CALL	BUMP			;BUMP UNALC PARMS FOR NEXT PASS
	CALL	TSTHST			;HOST = REQ ?
	JZ	WN1			;YES, CON'T TO FILL THE BFR
	MOV	AL,BYTE PTR FLAGS
	AND	AL,00000100B		;BIT 2,A   WRITE IN PROGRESS ?
	JZ	LAB22	
	CALL	XWRT			;YES, WRITE OLD DATA ONTO DISK
LAB22:	CALL	SETHST			;MAKE HOST = REQ
;
WN1:	MOV	AL,BYTE PTR FLAGS
	AND	AL,00000001B		;BIT  0,A          INTERVENING READ ?
	JZ	LAB23	
	CALL	XREAD			;YES, READ OLD UNALC DATA
LAB23:	JMPS	WXFER			;MOVE DATA TO BFR, EXIT
;
;   ALLOCATED WRITE
;
WALC:	XOR	AL,AL
	MOV	BYTE PTR URCNT,AL	;CLEAR UNALC RECORD COUNT
	CALL	TSTHST			;HOST = REQ ?
	JZ	WXFER			;YES -  MOVE DATA TO BFR, EXIT
	MOV	AL,BYTE PTR FLAGS
	AND	AL,00000100B		;BIT  2,A      WRITE IN PROGRESS ?
	JZ	LAB24	
	CALL	XWRT			;YES, WRITE OLD DATA ONTO DISK
LAB24:	CALL	SETHST			;MAKE HOST = REQ
	CALL	XREAD			;READ IN ALLOCATED DATA
	JMPS	WXFER			;MOVE NEW DATA IN BFR, EXIT
;
;   DIRECTORY WRITE
;
WDIR:	XOR	AL,AL
	MOV	BYTE PTR URCNT,AL	;CLEAR UNALC RECORD COUNT
	MOV	AL,BYTE PTR FLAGS
	AND	AL,11111110B		;RES   0,A          RESET 'RDOP' FLAG
	MOV	BYTE PTR FLAGS,AL
	AND	AL,00000100B		;BIT   2,A       WRITE IN PROGRESS ?
	JZ	LAB25	
	CALL	XWRT			;YES, WRITE OLD DATA ONTO THE DISK
LAB25:	MOV	AL,BYTE PTR FLAGS
	AND	AL,11111011B		;RES  2,A           CLEAR 'WIP' FLAG
	MOV	BYTE PTR FLAGS,AL
	CALL	SETHST			;MAKE HOST = REQ
	CALL	XREAD			;READ DIR DATA
	JZ	LAB26	
	RET				;RIF READ ERROR
LAB26:	CALL	GETDMA			;GET DMA ADR, SET POINTERS
	PUSH	DS
	MOV	DS, WORD PTR DMASEG	;GET THE CORRECT SEGMENT FOR [BX]
	MOV	SI,BX
	CLD
WDIRX:	LODS	AL			;<<<<<<<<<<<< OUTPUT 128 BYTES >>>>>>
	OUT	CTDP,AL
	LOOP	WDIRX
	POP	DS			;GET BACK OLD VALUE OF [DS]
	JMPS	XWRT			;WRITE DIR DATA, EXIT
;
;	---TEST HOST---
;
;   DETERMINES IF THE HOST DISK ADDRESS IS
;   THE SAME AS THE REQUESTED DISK ADDRESS.
;
;
TSTHST:	MOV	BX,(OFFSET HHTRK)
	CALL	DSKCMP			;TRACK & DRIVE THE SAME ?
	JZ	LAB27	
	RET				;RIF NO
LAB27:	MOV	AL,BYTE PTR RSA
	CMP	AL,BYTE PTR [BX]	;SECTOR THE SAME ?
	RET				;IF A = 0 THEN THEY MATCH
;
;	---SET HOST---
;
;   SETS THE HOST DISK ADDRESS TO BE THE
;   SAME AS THE REQUESTED DISK ADDRESS.
;
;
SETHST:	MOV	AL,BYTE PTR RRDSK
	MOV	BYTE PTR HHDSK,AL	;DRIVE #
	MOV	BX,WORD PTR RRTRK
	MOV	WORD PTR HHTRK,BX	;TRACK ADR
	MOV	AL,BYTE PTR RSA
	MOV	BYTE PTR HHSEC,AL	;SECTOR ADR
	RET
;
;	---BUMP---
;
;   BUMPS PARAMETERS FOR UNALLOCATED WRITES.
;   PARMS ARE CHANGED FOR THE NEXT PASS THRU
;   THE CODE (NOT THE CURRENT PASS).
;
BUMP:	MOV	BX,(OFFSET URCNT)	;UNALC RECORD COUNT
	DEC	BYTE PTR [BX]		;  DECR IT
	DEC	BX			;[BX] = URSEC
	INC	BYTE PTR [BX]		;  INCR IT
	MOV	AL,BYTE PTR [BX]
	CMP	AL,CPMSPT		;CPM SECTORS PER TRACK
	JNB	LAB28	
	RET				;RIF STAY ON SAME TRACK
LAB28:					;OVERFLOW TO NEXT TRACK
	MOV	BYTE PTR [BX],0		;RESET SECTOR ADR
	MOV	BX,WORD PTR URTRK
	INC	BX			;INC TRACK ADDRESS
	MOV	WORD PTR URTRK,BX
	RET
;
;	---GET DMA ADDRESS---
;
;   SETS THE CONTROLLER BUFFER ADDRESS TO THE CORRECT
;   STARTING POINT. ALSO SETS CX=128 & [BX] = DMADR.
;
;
GETDMA:	MOV	BX,WORD PTR DMADR	;DMA ADR
	MOV	CX,128			;BYTE COUNT
	MOV	AL,DBENB
	OUT	CTCSR,AL		;ENB DATA BFR
	MOV	AL,BYTE PTR RRSEC	;REQUESTED SECTOR
	ROR	AL,1
	MOV	AL,0
	JNB	GET1			;JIF USE 1ST HALF OF BFR
	MOV	AL,CL			;[CL] =128    USE 2ND HALF OF BFR
GET1:	OUT	CTBFR,AL		;SET CTLR DATA BFR ADR
	RET
;
;
;	======================================
;	** HARD DISK I/O & SUPPORT ROUTINES **
;	======================================
;	---READ A BLOCK---
;
XREAD:	MOV	BX,(OFFSET RTBL)	;READ CMD TBL
	CALL	DORW			;READ
;
XR1:	MOV	AL,0
	JNZ	LAB29	
	RET				;RIF READ/WRITE OK
LAB29:	INC	AL
	MOV	BYTE PTR ERFLG,AL	;SET ERROR FLAG
	RET
;
;	---WRITE A BLOCK---
;
XWRT:	MOV	BX,(OFFSET WTBL)	;WRITE CMD TBL
	CALL	DORW			;WRITE A SECTOR
	JMPS	XR1			;SET ERROR FLAG
;
;	---EXECUTE READ/WRITE COMMANDS---
;
DORW:	MOV	Word Ptr CTA,BX		;SAVE CMD TBL ADR
	CALL	XSEK			;SEEK TO NEW TRACK (IF REQUIRED)
	JZ	PAT1
	RET				;RIF SEEK FAILED
PAT1:
	CALL	XSEL			;HEAD SELECT
	MOV	BX,Word Ptr CTA
;
DO0:	MOV	AL,Byte Ptr [BX]
	MOV	Byte Ptr RETRY,AL	;SET RETRY COUNT
	INC	BX
	MOV	AL,Byte Ptr [BX]
	OUT	CTCSR,AL		;ENB CMP BFR
	INC	BX
	MOV	AL,Byte Ptr [BX]
	OUT	CTBFR,AL		;SET CMP BFR ADR
	INC	BX
	MOV	Word Ptr CTA,BX		;SAVE CMD TBL ADR
;
	MOV	BX,(Offset RCA)		;REAL TK ADR
	MOV	CH,3
DO1:	MOV	AL,Byte Ptr [BX]
	OUT	CTDP,AL			;PUT HDR INFO INTO CMP BFR
	INC	BX
	DEC	CH
	JNZ	DO1
	MOV	AL,Byte Ptr HHSEC
	OUT	CTDP,AL			;SET SECT ADR FOR COMPARE
;
DO2:	CALL	XRDY			;DRIVE READY ?
	JZ	PAT2	
	RET				;  RIF NO
PAT2:
	MOV	BX,Word Ptr CTA		;CMD TBL ADR
	MOV	AL,Byte Ptr [BX]	;A = CNTL BANK
	INC	BX
	MOV	CH,AL
	OUT	CTCSR,AL		;SLCT CNTL BANK
	MOV	AL,Byte Ptr [BX]
	OUT	CTBFR,AL		;SET START ADR
	INC	BX
	MOV	AL,CH
	OR	AL,START
	OUT	CTCSR,AL		;START R/W CMD
;
DO3:	CALL	WFD			;WAIT FOR READ/WRITE TO FINISH
	JNB	PAT3	
	RET				;ABORT IF TIMEOUT
PAT3:
	AND	AL,Byte Ptr [BX]	;TEST CTLR STATUS (0=OK)
	MOV	CH,AL
	IN	AL,DRCSR		;DRIVE STATUS
	AND	AL,WRTFLT
	JZ	PAT4	
	CALL	CLRDF			;CIF CLEAR DRIVE FAULT
PAT4:
	OR	AL,CH			;SET/CLEAR ERROR FLAG (0=OK)
	JNZ	PAT5	
	RET				;RIF READ/WRITE OK
PAT5:
	MOV	BX,(Offset RETRY)
	DEC	BYTE PTR [BX]		;DECR RETRY COUNT
	JNZ	DO2			;JIF RETRY READ/WRITE
;
;   SET ERROR FLAG
;
SEF:	MOV	AL,1			;A = ERROR FLAG
	OR	AL,AL			;SET 8080 FLAGS
	RET				;TAKE ERROR EXIT
;
;	---WAIT FOR DONE---
;
WFD:	PUSH	BX
	MOV	BX,0			;TIMEOUT DELAY COUNT
;
WFD1:	IN	AL,CTCSR		;CTLR STATUS
	ROR	AL,1
	JB	WFD2			;WAIT FOR DONE
	DEC	BX
	MOV	AL,BH
	OR	AL,BL
	JNZ	WFD1
;
	OUT	CTCSR,AL
	POP	BX
	MOV	AL,1
	OR	AL,AL
	STC
	RET
;
WFD2:	POP	BX
	IN	AL,CTCSR		;GET NON-CHANGING STATUS
	MOV	CH,AL
	XOR	AL,AL
	OUT	CTCSR,AL		;STOP CTLR
	MOV	AL,CH
	RET
;
;	---REZERO---
;
XTKZ:	MOV	BX,0
	MOV	Word Ptr RCA,BX
	CALL	TZT			;TEST IF TRK 0
	JNZ	PAT6
	RET
PAT6:	MOV	BX,511			;#OF CYL WE CAN COUNT ON CONTROLLER
	CALL	RTZ			;SEEK OUT
	JNB	PAT7	
	RET				;ABORT DRIVE NOT READY
PAT7:	JNZ	PAT8	
	RET				;IS AT 0
PAT8:	MOV	BX,LZONE+10-511
	CALL	RTZ			;TRY SECOND PUMP
	JNB	PAT9
	RET
PAT9:	JNZ	PAT10
	RET
PAT10:	JMPS	SEF			;ABORT RESTORE FAILED
;
;	SEEK OUTWARD
;
RTZ:	CALL	XRDY
	STC
	JZ	PAT11
	RET
PAT11:
	MOV	AL,BL
	OUT	LOSC,AL			;SET LSB OF SEEK COUNT
	MOV	AL,BH
	OUT	HISC,AL			;SET MSB
	MOV	AL,SKOUT
	OUT	EXTCMD,AL		;SET SEEK DIRECTION OUTWARD
	MOV	AL,HSKCMD
	OUT	DRCSR,AL		;ISSUE SEEK
	CALL	WSC
	JNB	TZT
	RET
;
TZT:	IN	AL,DRCSR		;GET DRIVE STATUS
	AND	AL,TK00
	XOR	AL,TK00
	RET
;
XSTZ:	MOV	AL,BYTE PTR FLAGS
	AND	AL,00000100B
	JNZ	XSTZ1
	MOV	BYTE PTR FLAGS,AL
XSTZ1:	MOV	BX,0
	MOV	WORD PTR RRTRK,BX
	XOR	AL,AL
	RET
;
;
;	---SEEK---
;
XSEK:	MOV	AL,3
	MOV	Byte Ptr SKRTC,AL	;SET SEEK RETRY COUNT
;
XSEK1:	MOV	BX,Word Ptr HHTRK	;REQUESTED TRACK
	SHR	BX,1
	CMP	BX,MAXCYL
	JNAE	XSEK2
	JMP	SEF			;ABORT IF INVALID ADDRESS
;
XSEK2:	MOV	DX,Word Ptr RCA		;LOAD UP CURRENT REAL ADR
	MOV	Word Ptr RCA,BX		;SAVE NEW ADDRESS
	XCHG	BX,DX
	SUB	BX,DX
	JNZ	PAT14	
	RET				;RETURN IF SAME
PAT14:	MOV	CH,1			;DIR = OUT
	JNB	XSEK3			;OK SEEK OUTWARD
;
	MOV	CH,3			;SEEK INWARD
	MOV	AL,BL
	NOT	AL			;MAKE SEEK POSITIVE
	MOV	BL,AL
	MOV	AL,BH
	NOT	AL
	MOV	BH,AL
	INC	BX
;
XSEK3:	MOV	AL,CH			;GO TO SEEKING INWARD
	MOV	Byte Ptr SKDIR,AL
	MOV	DX,512
	CMP	BX,DX
	JNB	XSEK4			;JIF DOUBLE PUMP IS REQ
	CALL	PSK			;DO PARTIAL SEEK
	JZ	PAT15
	RET
PAT15:	JMPS	XSEK5
;
XSEK4:	DEC	DX			;DX = 511
	SUB	BX,DX
	MOV	Word Ptr RSKNT,BX	;SAVE RESIDUAL COUNT
	XCHG	BX,DX
	CALL	PSK
	JZ	PAT16	
	RET				;ABORT IF SEEK FAILED
PAT16:	MOV	BX,Word Ptr RSKNT
	CALL	PSK			;SEND THE REST
	JZ	XSEK5
	RET
;
;					;SEEK VERIFY
XSEK5:	MOV	AL,3
	MOV	Byte Ptr VSRTC,AL	;SET RETRY COUNT
	MOV	AL,CBENB
	OUT	CTCSR,AL		;ENABLE BANK ZERO CMP BFR
	MOV	AL,VCA
	OUT	CTBFR,AL		;SET CMP BFR ADR
	MOV	BX,Word Ptr RCA		;REAL (CURR) CYL ADR
	MOV	AL,BL
	OUT	CTDP,AL			;SET CYL ADR, LSB
	MOV	AL,BH
	OUT	CTDP,AL			;SET CYL ADR, MSB
XSEK6:	MOV	AL,VSA
	OUT	CTBFR,AL		;SET M/CODE START ADR
	MOV	AL,START
	OUT	CTCSR,AL		;START VERIFY
	CALL	WFD			;WAIT FOR DONE
	AND	AL,0CH			;TEST CTLR STATUS
	JNZ	PAT18	
	RET				;RIF VERIFY OK
PAT18:	MOV	BX,(Offset VSRTC)
	DEC	BYTE PTR [BX]		;DECR RETRY COUNT
	JNZ	XSEK6			;JIF RETRY SEEK VERIFY
					; VERIFY FAILED
	CALL	XTKZ			;RESTORE
	MOV	BX,(Offset SKRTC)
	DEC	BYTE PTR [BX]		;DECR RETRY COUNT
	JZ	PAT19	
	JMP	XSEK1			;JIF RETRY SEEK
PAT19:	OR	AL,1			;SET ERROR FLAG
	RET				;ABORT
;
;   PARTIAL SEEK
;
PSK:	CALL	XRDY			;DRIVE READY ?
	JZ	PAT20
	RET
PAT20:	MOV	AL,BL
	OUT	LOSC,AL			;SET SEEK COUNT, LSB
	MOV	AL,BH
	OUT	HISC,AL			;   * MSB
	MOV	AL,Byte Ptr SKDIR
	OUT	EXTCMD,AL		;SET SEEK DIRECTION
	MOV	AL,3
	OUT	DRCSR,AL		;ISSUE SEEK CMD
;
;	 ---> FALL THRU TO 'WSC' <---
;
;	---WAIT FOR SEEK COMPLETE---
;
;
WSC:	PUSH	BX			;SAVE REGS
	PUSH	CX
	MOV	BX,0			;TIME-OUT DELAY COUNT
	MOV	CH,6	;WAS 3 FOR XCOMP;..DITTO
;
WSC1:	IN	AL,DRCSR		;DRIVE STATUS
	RCL	AL,1
	JB	WSC2			;JIF SEEK DONE
	DEC	BX			;DECR DELAY COUNT
	MOV	AL,BH
	OR	AL,BL
	JNZ	WSC1			;JIF CON'T WAITING
	DEC	CH
	JNZ	WSC1
					; TIME-OUT ERROR
	POP	CX			;RESTORE REGS
	POP	BX
	MOV	AL,1
	OR	AL,AL			;SET CPM ERROR FLAG
	STC				;SET INTERNAL ERROR FLAG
	RET
;
WSC2:	POP	CX			;RESTORE REGS
	POP	BX
	XOR	AL,AL			;SET FLAG = OK
	RET
;
;
;
;	---CLEAR DRIVE FAULT---
;
CLRDF:	XOR	AL,AL
	OUT	EXTCMD,AL		;DE-SELECT (FALL THRU TO 'XSEL' TO
					;RE-SELECT THE DRIVE)
;
;	---HEAD SELECT---
;
XSEL:	MOV	AL,Byte Ptr HHTRK	;REQUESTED TRACK
	AND	AL,1			;2 HEADS
	MOV	Byte Ptr RHD,AL		;SAVE REAL HEAD #
	ADD	AL,AL			;SHIFT HEAD # LEFT TWICE FOR H/W
	ADD	AL,AL
	OR	AL,1			;TO MAINTAIN DRIVE SLCT
	OUT	EXTCMD,AL		;SELECT HEAD 0 OR 1
	RET
;
;	---DRIVE READY TEST---
;
XRDY:	IN	AL,DRCSR		;DRIVE STATUS
	AND	AL,1			;DRIVE RDY BIT
	XOR	AL,1			;  MAKE IT LO-TRUE
	JNZ	PAT21	
	RET				;RIF DRIVE READY
PAT21:	OR	AL,1			;SET ERROR FLAG
	RET
;
DSKCMP:	MOV	DX,(OFFSET RRTRK)	;GET REQUESTED TRACK
	MOV	CH,3
DC1:	MOV	SI,DX
	MOV	AL,[SI]
	CMP	AL,BYTE PTR [BX]
	JZ	LAB43
	RET
LAB43:	INC	BX
	INC	DX
	DEC	CH
	JNZ	DC1
	RET
;
;
;	======================================
;	 	FLOPPY DISK ROUTINES
;	======================================
;
FSELDSK:DEC	AL			;FOR FLOPPY MAKE B:=A: (OR C:== B:) 
	MOV	CL,AL			; (NOTE A:, B: & C: DRIVES ONLY)
	OR	AL,AL			;IF REQ DRIVE IS A: THEN [A] = 0
	JNZ	BBBB			;MUST BE B: DRIVE
	MOV	AL,BYTE PTR ADRIVE	;IS IT THE FIRST TIME FOR THIS DRIVE
	CMP	AL,0FFH
	JNZ	LAB44	
	CALL	GETTYPE
LAB44:	MOV	BYTE PTR ADRIVE,AL	;STORE DENSITY FLAG
	JMPS	ALLOK
BBBB:	MOV	AL,BYTE PTR BDRIVE	;IS IT THE FIRST TIME FOR THIS DRIVE
	CMP	AL,0FFH
	JNZ	LAB45	
	CALL	GETTYPE
LAB45:	MOV	BYTE PTR BDRIVE,AL	;STORE DENSITY FLAG
;
ALLOK:	OR	AL,CL			;MIX DRIVE TYPE WITH DRIVE#
	MOV	BYTE PTR UNIT,AL	;STORE IT FOR SECTOR R/W ROUTINES ETC
	TEST	AL,40H			;BIT 6,A
	JNZ	LAB46
	MOV	AL, BYTE PTR RRDSK	;GET ORRIGIONAL DISK REQUESTED
	RET				;RET WITH TABLE OFFSET B:=B: & C:=C:
;
LAB46:	MOV	AL,00000011B		;FOR DOUBLE DENS DISKS WE MUST USE 
	ADD	AL,CL			;THE LOOKUP TABLE FOR DRIVES D: & E:
	RET				;RETURNS TABLE OFFSET B:=D: & C:=E:
;
GETTYPE:MOV	AL,CL			;FIND OUT TYPE OF DRIVE
	CALL	UNITSL
	JNZ	HB101			;IF NZ PROBLEMS ABORT
	MOV	AL,BYTE PTR UNIT
	AND	AL,01000000B		;GET DENSITY FLAG
	RET
;
HB101:	MOV	BX,0			;ABORT BECAUSE CANNOT GET DISK TYPE
	POP	AX			;DROP STACK BACK ONE LEVEL
	XOR	AL,AL			;JUST IN CASE
	DEC	AL
	RET

; THIS ROUTINE SETS UP THE FLOPPY DISK UNIT BYTE
; THE REQUIRED DRIVE IS IN [A]
;
UNITSL:	MOV	CH,5			;WILL TRY 5 TIMES
	AND	AL,0FH
	OR	AL,40H			;COME UP DEFALT IN 8" DD
	MOV	BYTE PTR UNIT,AL
	MOV	BX,WORD PTR DMADR
	MOV	WORD PTR TEMP2,BX
	CALL	USL1
	MOV	BX,WORD PTR TEMP2
	MOV	WORD PTR DMADR,BX
	MOV	AL,BYTE PTR UNIT
	RET
;
USL1:	PUSH	CX
	PUSH	BX
	MOV	WORD PTR SPSV,SP	;TEMP SAVE SP IN SPSV
	POP	BX
	CALL	DRVSET			;SELECT DRIVE IN HARDWARE
	CALL	IDRD			;TRY READING TRACK ID
	POP	CX
	JNZ	LAB48	
	RET				;IF CORRECT DENSITY WILL BE Z
LAB48:	DEC	CH			;DECREASE 5.......0 IF Z THEN ERROR
	JZ	SPECIAL
	CALL	CHGTYP
	JMPS	USL1
;
SPECIAL:XOR	AL,AL			;MAY FOR SPECIAL SECTOR SIZE ETC
	DEC	AL
	RET				;RET NZ SO SELDSK KNOWS WAS PROBLEM
;
CHGTYP:	MOV	AL,BYTE PTR UNIT
	ADD	AL,01000000B		;TOGGLE DENSITY BIT
	AND	AL,01111111B		;CLEAR BIT 7
	MOV	BYTE PTR UNIT,AL
	RET
;
;	READ A SECTOR
FREAD:	MOV	CX,301H
READ1:	PUSH	CX
	CALL	RDSC
	POP	CX
	JNZ	LAB49
	RET
LAB49:	CALL	FRETRY
	JMPS	READ1
;
;	WRITE A SECTOR
FWRITE:	MOV	CX,301H			;RTRY= 3 RSEEK = 1 
WRITE1:	PUSH	CX
	CALL	WRSC
	POP	CX
	JNZ	LAB50
	RET
LAB50:	CALL	FRETRY
	JMPS	WRITE1
;
FRETRY:	DEC	CH
	JNZ	RETRY2
	MOV	AL,BYTE PTR RTRY
	MOV	CH,AL
	DEC	CL
	JNS	RETRY1
	POP	AX			;DROP STACK BACK ONE LEVEL
	XOR	AL,AL			;IF PROBLEM
	INC	AL
	RET
;
RETRY1:	PUSH	CX
	CALL	HOME1
	POP	CX
RETRY2:	RET
;
HOME1:	MOV	WORD PTR SPSV,SP	
	MOV	AL,RSCMD
	CALL	SEEK4
	XOR	AL,AL
	RET
;
;	SELECT DRIVE IN HARDWARE
;
DRVSET:	MOV	DX,OFFSET UNIT
	PUSH	SI
	MOV	SI,DX
	MOV	AL,[SI]
	AND	AL,0E0H
	MOV	CL,AL			;STORE DRIVE TYPE IN [CL]
	MOV	SI,DX
	MOV	AL,[SI]
	AND	AL,03
	MOV	CH,AL			;STORE DRIVE # IN [CH]
	MOV	AL,1
	JZ	DRVSEL
CKDRV1:	ROL	AL,1
	DEC	CH
	JNZ	CKDRV1
DRVSEL:	OR	AL,CL			;COMBINE TYPE & DRIVE#
	AND	AL,7FH
	MOV	CH,AL			;[CH] CONTAINS INFO FOR HARDWARE
	MOV	AL,STDSDT		;SETUP FOR SD
	MOV	BYTE PTR COUNT,AL	;STORE AS 26 SECTORS/TRACK
	MOV	AL,40H			;WAS IT DD
DRV1:	CMP	AL,CL
	JNZ	CKDRV
	MOV	AL,STDDDT		;SETUP FOR DD 
	MOV	BYTE PTR COUNT,AL	;SET TO 50 SECTORS/TRACK
CKDRV:	MOV	AL,CH			;GET HARDWARE SELECT DATA
	NOT	AL			;HARDWARE IS INVERTED
	OUT	SELECT,AL
	MOV	SI,DX
	MOV	AL,[SI]
	MOV	BYTE PTR UNITCK,AL
	CALL	DELAY
	POP	SI
RDYCK:	IN	AL,STATUS
	AND	AL,80H
	JNZ	END2X
	RET
END2X:	JMP	END2
;
;	READ PRESENT DISK ADDRESS
IDRD:	CALL	WAIT
	MOV	BX,OFFSET IDSV		;WILL STORE THE 6 ID BYTES HERE
	MOV	CX,6			;READ 6 BYTES
	MOV	AL,0F8H
	MOV	BYTE PTR ERMASK,AL
	CALL	SWEB
	MOV	AL,RDACMD		;DO THE ID READ
	CALL	RDSCO
	MOV	AL,BYTE PTR IDSV
	CMP	AL,NTRKS		;IS IT REASONABLE
	JNAE	LAB51	
	JMP	SEEK0
LAB51:	OUT	TRACK,AL
	XOR	AL,AL
	RET
;
DELAY:	MOV	AL,040H			;DELAY ~32 MS (SEEMS NOT CRITICAL)
DELAY1:	MOV	CH,0
M0:	DEC	CH
	JNZ	M0
	DEC	AL
	JNZ	DELAY1
	RET
;
;	READ SECTOR COMMAND
RDSC:	CALL	DRINIT
	MOV	AL,RDCMD
RDSCO:	MOV	BYTE PTR CMDSV,AL
	CLI
	OUT	CMD,AL
	PUSH	ES
	PUSH	DI
	MOV	ES,WORD PTR DMASEG	;GET CORRECT SEGMENT
	MOV	DI,BX
	CLD
RDSCX:	IN	AL,DATA			;>>>>>>>>>>READ 128 BYTES<<<<<<<<<<<<
	STOS	AL			;NOTE POINTER IS [ES] [DI]
	LOOP	RDSCX
	POP	DI
	POP	ES			;GET BACK OLD VALUE OF [DS]
	STI
	JMPS	ENDX
;
;
;	WRITE SECTOR COMMAND
WRSC:	CALL	DRINIT
	MOV	AL,WRCMD
	MOV	BYTE PTR CMDSV,AL
	CLI
	OUT	CMD,AL
	PUSH	DS
	PUSH	SI
	MOV	DS, WORD PTR DMASEG	;GET CORRECT SEGMENT
	MOV	SI,BX
	CLD
WRSCX:	LODS	AL			;>>>>>>>>> WRITE 128 BYTES <<<<<<<<<
	OUT	DATA,AL
	LOOP	WRSCX
	POP	SI
	POP	DS			;GET BACK OLD VALUE OF [DS]
	STI
;
;	END  OF COMMAND
ENDX:	CALL	WAIT
	IN	AL,STATUS
	MOV	DH,AL
	MOV	AL,BYTE PTR ERMASK
	AND	AL,DH
	JNZ	END1
	RET
END1:	MOV	AL,DH
END2:	MOV	BYTE PTR ERSTAT,AL
	CALL	DELAY
	MOV	SP,WORD PTR SPSV	
	XOR	AL,AL
	DEC	AL			;RETURN NZ TO INDICATE AN ERROR
	MOV	BYTE PTR UNITCK,AL
	RET
;
;
;	DRIVE INITIALIZATION
;
DRINIT:	POP	BX
	MOV	WORD PTR SPSV, SP	
	PUSH	BX
	MOV	AL,BYTE PTR UNIT
	MOV	DH,AL
	MOV	AL,BYTE PTR UNITCK
	CMP	AL,DH
	JZ	DINIT1
	CALL	DRVSET
	CALL	IDRD
DINIT1:	CALL	SEEK
	MOV	AL,0FEH
	MOV	BYTE PTR ERMASK,AL
;
TRINT:	MOV	BX,WORD PTR DMADR	;SETUP DMA ADDRESS AND BYTE COUNT
	MOV	AL,BYTE PTR RRSEC
	OUT	SECTOR,AL
	MOV	CX,NBYTES		;USED BY LOOP INST IN SEC RD/WRT
;
SWEB:	IN	AL,SELECT		;ENABLE WAIT STATES
	AND	AL,7FH
	OUT	SELECT,AL
	RET
;
;	SEEK TRACK
;
SEEK:	CALL	RDYCK
	MOV	CL,NTRKS		;MUST BE REASONABLE TRACK #
	MOV	AL,BYTE PTR RRTRK	;ALWAYS < 0FFH TRACKS FOR FLOPPY
	CMP	AL,CL
	JB	SEEK1
SEEK0:	MOV	AL,0FH
	JMPS	END2
SEEK1:	MOV	CL,AL
	IN	AL,TRACK
	CMP	AL,CL
	JNZ	LAB53	
	RET				;IF SAME TRACK NO NEED TO SEEK
LAB53:	MOV	AL,SKCMD
SEEK4:	MOV	BYTE PTR CMDSV,AL
	MOV	CH,210
S0:	DEC	CH
	JNZ	S0
	CALL	WAIT
	MOV	AL,BYTE PTR RRTRK
	OUT	DATA,AL
	MOV	AL,80H
	MOV	BYTE PTR ERMASK,AL
	MOV	AL,BYTE PTR CMDSV
	OUT	CMD,AL
	MOV	CH,10
D0:	DEC	CH
	JNZ	D0
	CALL	ENDX
	CALL	DELAY
	MOV	AL,BYTE PTR CMDSV
	CMP	AL,RSCMD		;NO NEED TO CHECK RESTORE COMMAND
	JNZ	LAB54
	RET
LAB54:	IN	AL,STATUS
	AND	AL,10H
	JNZ	SEEK2
	IN	AL,TRACK
	CMP	AL,CL
	JNZ	SEEK2
	RET
SEEK2:	MOV	AL,20H
END2JP:	JMP	END2
;
WAIT:	MOV	DL,0
	PUSH	CX
	MOV	CL,2
WAIT2:	IN	AL,STATUS
	AND	AL,1
	JZ	DWAIT
	DEC	CH
	JNZ	WAIT2
	DEC	DL
	JNZ	WAIT2
	DEC	CL
	JNZ	WAIT2
	POP	CX
	IN	AL,SELECT		;IF BY THIS TIME NOT READY FORCE
	OR	AL,80H			;A HARDWARE RESET
	OUT	RSET,AL
F0:	DEC	CH
	JNZ	F0
	IN	AL,RSET
	CALL	FRCINT
	MOV	AL,RSCMD
	CALL	SEEK4
	MOV	AL,0FEH
	JMPS	END2JP
;
;	DISABLE WAIT STATES
DWAIT:	POP	CX			;TO BALANCE THE ABOVE PUSH IN WAIT
	IN	AL,SELECT
	OR	AL,80H
	OUT	SELECT,AL
	RET
;
;
;
;	FORCE CHIP INTERUPT
FRCINT:	MOV	AL,0D0H
	OUT	CMD,AL
	MOV	AL,10
FRC1:	DEC	AL
	JNZ	FRC1
	IN	AL,STATUS
	RET
;
;>>>>>>>>>>>>>>>> MDISK SECTOR READ AND WRITE ROUTINES <<<<<<<<<<<<<<<<<
;
MREAD:	MOV	CL,RDSECTOR		;[CL] = READ SECTOR COMMAND
	CALL	MRDCMD			;SEND IT TO THE RAMDISK
	JNB	MRDERR
	JMP	RWERR			;IF FAIL TO SEND THEN ERROR ROUTINE.
MRDERR:	CALL	SEND@TRKSEC		;ELSE SEND TRACK AND SECTOR TO RAMDSK
					;SET UP REGS FOR SECTOR TRANSFER:
	MOV	BX,WORD PTR DMADR	;[BX] = DMA ADDRESS
	PUSH	ES			;CPM86 DOES NOT SAVE ES IN BDOS
	MOV	ES,WORD PTR DMASEG
	MOV	CX,NBYTES		;[CX] = 128 = # BYTES TO READ
	MOV	DI,BX			;>>>>>>>>> INPUT 128 BYTES <<<<<<<<
RDLOOP:	CALL	RDREAD			;GET NEXT SECTOR BYTE
	STOS	AL			;DEPOSIT INTO MEMORY
	LOOP	RDLOOP			;LOOP FOR ALL BYTES [CX TO 0]
	POP	ES			;GET BACK ES
	CALL	RDREAD			;GET THE RESULT BYTE
	OR	AL,AL			;SHOULD BE ALL 0 BITS IF GOOD R/W
	JZ	MDONE
	JMP	RWERR			;[A] = 0 ON RETURN IF GOOD R/W
MDONE:	RET
;
;
MWRITE:	MOV	CL,WRTSECTOR		;[CL] = WRITE SECTOR COMMAND
	CALL	MRDCMD
	MOV	BX,(OFFSET MD@OFFLINE)	;IF RAMDISK OFFLINE SAY SO
	JNB	MWNER
	JMP	RWERR1
MWNER:	CALL	SEND@TRKSEC		;ELSE SEND TRACK AND SECTOR TO RAMDSK
					;SET UP REGS FOR SECTOR TRANSFER:
	MOV	BX,WORD PTR DMADR	;[BX] = DMA ADDRESS
	PUSH	DS
	MOV	DS,WORD PTR DMASEG
	MOV	CX,NBYTES		;[CX] = 128 = # BYTES TO READ
	MOV	SI,BX			;>>>>>>>>> OUTPUT 128 BYTES <<<<<<<<
WRLOOP:	LODS	AL
	MOV	AH,AL			;TEMP STORE DATA HERE
WRLOOP1:IN	AL,CTRLPORT		;GET STATUS BYTE
	AND	AL,1			;CHECK FOR RAMDISK READY TO RECEIVE
	JZ	WRLOOP1
	MOV	AL,AH
	OUT	DATAPORT,AL
	LOOP	WRLOOP			;LOOP FOR ALL BYTES [CX TO 0]
	POP	DS			;GET BACK DS
	CALL	RDREAD			;GET THE RESULT BYTE
	OR	AL,AL			;SHOULD BE ALL 0 BITS IF GOOD R/W
	JZ	MDONE
	JMP	RWERR			;[A] = 0 ON RETURN IF GOOD R/W
;

;SENDS THE TRACK AND SECTOR FOR THE NEXT R/W OPERATION TO THE
SEND@TRKSEC:
	MOV	CX,WORD PTR RRSEC	;GET THE SECTOR TO [BC]
	CALL	RDWRITE			;SEND THE LOW BYTE FIRST
	MOV	CL,CH			;THEN THE HIGH BYTE
	CALL	RDWRITE
	MOV	CX,WORD PTR RRTRK	;GET TRACK # TO [CL]
	JMPS	RDWRITE			;SEND IT AND RETURN...
;
; ROUTINE SENDS A CHARACTER TO THE RAMDISK:
RDWRITE:
	IN	AL,CTRLPORT		;GET STATUS BYTE
	AND	AL,1			;CHECK FOR RAMDISK READY TO RECEIVE
	JZ	RDWRITE
	MOV	AL,CL			;GET OUTPUT BYTE
	OUT	DATAPORT,AL		;SEND IT
	RET
;
; ROUTINE READS 1 CHARACTER FROM THE RAMDISK:
RDREAD:	IN	AL,CTRLPORT		;WAIT UNTIL PORT IS READY
	AND	AL,80H
	JZ	RDREAD			;LOOP UNTIL INPUT STATUS IS TRUE
	IN	AL,DATAPORT		;GET CHARACTER WAITING
	RET
;
; ROUTINE GETS RAMDISK INPUT STATUS:
RDINSTAT:IN	AL,CTRLPORT		;GET STATUS BYTE
	AND	AL,80H			;SEE IF DATA WAITING
	RET				;WITH STATUS Z FLAG
;
; ROUTINE SENDS A COMMAND TO THE RAMDISK:
MRDCMD:	CALL	RDWRITE			;SEND COMMAND TO THE RAMDISK
	CALL	RDWAIT			;WAIT FOR ECHO
	JNB	LM4	
	RET				;RETURN ON TIMEOUT OR NO BYTE MATCH..
LM4:	MOV	AL,CL			;GET COMMAND JUST SENT
	NOT	AL			;AND COMPLEMENT IT
	MOV	CL,AL
	CALL	RDWRITE			;SEND IT
	CALL	RDWAIT			;WAIT FOR ECHO
	RET				;WITH FLAGS SET
;
; ROUTINE WAITS FOR ECHO RESPONSE FROM HOST FOR A SPECIFIED DELAY
; TIME AND IF NO RESPONSE IS GOTTEN IT RETURNS WITH AN ERROR FLAG:
RDWAIT:	PUSH	CX			;SAVE [CX]
	MOV	CX,CMDDLY		;LOAD DELAY CONSTANT
RDW0:	CALL	RDINSTAT		;GET INPUT STATUS
	JNZ	RDW2			;Z = 0 MEANS WE GOT SOMETHING
	DEC	CX			;ELSE DROP DELAY COUNT
	MOV	AL,CL			;CHECK FOR DELAY TIMEOUT
	OR	AL,CH
	JNZ	RDW0			;KEEP CHECKING HOST IF NO TIMEOUT
RDW1:	POP	CX			;SYNCHRONIZE STACK
RDW1A:	STC				;SET ERROR FLAG
	RET
RDW2:	CALL	RDREAD			;GET ECHOED CHARACTER
	POP	CX			;CHARACTER SENT BACK TO [CX]
	CMP	AL,CL			;IS ECHOED CHAR = CHAR SENT ?
	JNZ	RDW1A			;NO -- RETURN ERROR...
	RET
;
; R/W ERROR  HERE TO INSPECT RESULT BYTE BITS FOR MESSAGE TO DISPLAY:
RWERR:	TEST	AL,01000000B
	JZ	RW3
	MOV	BX,(OFFSET MD@WP)
RWERR1:	CALL	PMSG			;DISPLAY MESSAGE IF SO
RWERR2:	MOV	AL,1			;RETURN ONLY 0 OR 1 FOR CPM86
	RET
;
RW3:	TEST	AL,10000000B		;CHECK FOR TRACK / SECTOR ERROR
	MOV	BX,(OFFSET MD@TRKSEC)
	JNZ	RWERR1
;
	TEST	AL,00100000B		;CHECKSUM ERROR ?
	MOV	BX,(OFFSET MD@CKSUM)
	JNZ	RWERR1
;
	JMP	RWERR2			;UNKNOWN ERROR
;
;
;<<<<<<<<<<<<<<<<<<<<<< MAIN CONSOL OUTPUT ROUTINE >>>>>>>>>>>>>>>>>>>>>>>>>
;		NOTE THIS CODE IS SPECIFIC FOR MY SYSTEM
;
CO:	IN	AL,IOBYTE
	TEST	AL,1H		;BIT 0,A  CHECK IF OUTPUT TO LIST IS ALSO REQ
	JZ	LOX
	TEST	AL,8H		;BIT 3,A  CHECK IF PRINTER IS CONSOL
	JNZ	COX1
	JMP	LO
COX1:	TEST	AL,10H		;BIT 4,A  KILL LF'S IF THIS IS 0
	JNZ	SDCONO
	MOV	AL,CL
	CMP	AL,LF
	JZ	SDCON5		;KILL LF'S
	PUSH	CX		;ALL OTHERE CHARACTRS SEND EOL THEN CHARACTER
	MOV	CL,']'-40H	;FOR CLEAR TO END OF LINE
	CALL	SDCONO		;BECAUSE EOL IS SENT FOR EACH CHARACTER THE
	POP	CX		;TYPE RATE IS NICELY SLOWED DOWN TO ~ 60 BAUD
	JMPS	SDCONO		;AT NO FURTHER EXPENSE |
SDCON5:	MOV	AL,CL
	RET
;
LOX:	CALL	SDCONO		;OUTPUT TO BOTH PRINTER & CONSOLE
	JMP	LO
;
SDCONO:	IN	AL,SDSTAT	;SD SYSTEMS VIDIO BOARD PORT
	AND	AL,4H
	JZ	SDCONO
	MOV	AL,CL
	CMP	AL,07H		;IS IT A BELL
	JZ	BELL1
	CMP	AL,0H		;SD BOARD CANNOT TAKE A NULL
	JNZ	LX2
	RET

LX2:	OUT	SDDATA,AL
	IN	AL,IOBYTE
	TEST	AL,20H		;BIT 5,A SEE IF TIME DELAY REQ WITH CO:
	JNZ	LX3
	MOV	AL,20
	CALL	TDELAY
LX3:	MOV	AL,CL		;BE SURE TO RETURN WITH [AL] CONTAINING CHAR
	RET
;
BELL1:	MOV	AL,06H		;SEND A BELL
	OUT	SDDATA,AL
	MOV	AL,3FH
	CALL	TDELAY
	MOV	AL,CL
	OUT	SDDATA,AL
	RET
;
;
TDELAY:	DEC	AL		;GENERAL COUNT DOWN TIME DELAY
	JNZ	LX4	
	RET			;LENGTH SET IN [A]
LX4:	PUSH	AX
	MOV	AL,05H
MORE:	DEC	AL
	PUSH	AX
	XOR	AL,AL
MORE2:	DEC	AL
	JNZ	MORE2
	POP	AX
	JNZ	MORE
	POP	AX
	JMPS	TDELAY
;
; 
;<<<<<<<<<<<<<<<<<<< MAIN CONSOL STATUS ROUTINE >>>>>>>>>>>>>>>>>>>>>>
;
CSTS:	IN	AL,KEYSTAT
	AND	AL,02H
	JNZ	CST1
	RET				;RETURN WITH 0 IN [A] IF NOTHING THERE
CST1:	DEC	AL
	RET				;RETURN WITH 0FFH IN [A] IF SOMETHING
;
;
;<<<<<<<<<<<<<<<<<<<< MAIN CONSOL INPUT ROUTINE >>>>>>>>>>>>>>>>>>>>
;
CI:	CALL	CSTS		;NEED CONSTAT TO CLEAN UP SHIFT KEYS ETC
	JZ	CI
	IN	AL,KEYIN
	AND	AL,7FH
	RET
;
;<<<<<<<<<<<<<<<<<<<<<< MAIN PRINTER STATUS ROUTINE >>>>>>>>>>>>>>>>>>>>>>>>>
;
LSTAT:	IN	AL,CENTSTAT		;FIRST FIND WHICH PRINTER IS SELECTED
	TEST	AL,2
	JNZ	CENSTAT
	TEST	AL,20H
	JNZ	TRANSTAT
	XOR	AL,AL			;NONE SELECTED
	DEC	AL
	RET

CENSTAT:AND	AL,00001111B	;XXXX0110 IS READY (BIT 3=PAPER BIT 2=FAULT
	CMP	AL,00000110B		;BIT 1=SELECT  BIT 0=BUSY
	JZ	LSTAT1
	XOR	AL,AL
	RET

TRANSTAT:AND	AL,11110000B	;0110XXX IS READY (BIT 7=ALERT BIT 6=FAULT
	CMP	AL,01100000B		;BIT 5=SELECT BIT 4=BUSY
	JZ	LSTAT1
	XOR	AL,AL
	RET

LSTAT1:	XOR	AL,AL		;PUT 0FFH IN [A] IF READY & NO ZERO FLAG
	DEC	AL
	RET
;
;<<<<<<<<<<<<<<<<<<<<<< MAIN PRINTER OUTPUT ROUTINE >>>>>>>>>>>>>>>>>>>>>>>>>
;
LO:	CALL	LSTAT
	JZ	LO
	MOV	AL,0FFH
	OUT	CENTSTROBE,AL
	MOV	AL,CL
	OUT	CENTOUT,AL
	IN	AL,CENTSTAT
	TEST	AL,2
	JNZ	LCENT
	TEST	AL,20H
	JNZ	LTRANS
	RET				;NO STROBE SINCE NOT SELECTED
;
LCENT:	MOV	AL,11111110B		;STROBE FOR CENTRONICS
	JMPS	OVERLS
LTRANS:	MOV	AL,11111101B
OVERLS:	OUT	CENTSTROBE,AL
	MOV	AL,0FFH
	OUT	CENTSTROBE,AL
	RET
;
;
POO:	RET			;NO PUNCH OUTPUT AT THE MOMENT
RI:	MOV	AL,1AH		;NO READER AT THE MOMENT
	RET
;
SCO:	MOV	AL,15H		;SEND CHARACTER TO TALKER
	OUT	TALKSTAT,AL
	IN	AL,TALKSTAT
	AND	AL,02H
	JZ	SCO
	MOV	AL,CL
	OUT	TALKOUT,AL
	RET
;
SMSG:	MOV	AL,[BX]		;SPEAK A STRING
	TEST	AL,AL
	JZ	RETURS
	MOV	CL,AL
	CALL	SCO
	INC	BX
	JMP	SMSG
RETURS:	MOV	CL,CR
	JMP	SCO
;
;
;
LAB57	EQU	$
;
;---------------------> START OF DATA SEGMENT <---------------------
;
;
		DSEG
		ORG OFFSET LAB57
;
;
;	---MESSAGES---
;
;
SIGNON	 DB	1AH,1H,10H,11H,LF,09H,09H
	 DB	'128K CP/M-86 V1.1  (With Intelladisk)',CR,LF
CLEANUP	 DB	1H,10H,11H,17H,07H,0H
SPEAKON  DB	'1 HUNDRED AND TWENTY EIGHT KAY  C  P  M EIGHTY SIX ',0
DRNRDY	 DB	CR,LF,'DRIVE NOT READY',0
INT_TRP  DB	CR,LF,'INTERRUPT TRAP HALT AT:- ',0H
INT0_TRP DB	CR,LF,'DIVIDE TRAP HALT AT:- ',0H
INT4_TRP DB	CR,LF,'OVERFLOW TRAP HALT AT:- ',0H
;
; MEMORY DISK ERROR MESSAGES:
MD@OFFLINE DB	' MEMORY DISK APPEARS TO BE OFFLINE',0
MD@WP	DB	' MEMORY DISK WRITE-PROTECTED',0
MD@CKSUM DB	' MEMORY DISK CHECKSUM ERROR',0
MD@TRKSEC DB	' MEMORY DISK TRACK / SECTOR OUT OF RANGE',0
;
;
;	---MICROCODE COMMAND TABLES FOR XCOMP CONTROLLER---
;WRITE
WTBL	DB	5			;RETRY COUNT
	DB	5			;CMP BFR ENB
	DB	0E6H			;CMP BFR ADR
	DB	BANK1			;CNTL BANK
	DB	0D3H			;START ADR
	DB	0EH			;STATUS MASK
;
;READ
RTBL	DB	10			;RETRY COUNT
	DB	4			;CMP BFR ENB
	DB	0EAH			;CMP BFR ADR
	DB	BANK0			;CNTL BANK
	DB	0D7H			;START ADDRESS
	DB	0EH			;STATUS MASK

;	---PROGRAM STORAGE---
;
SEGTABLE DB	1			;SYSTEM MEMORY TABLE
	 DW	TPASEG			;FIRST SEGMENT STARTS AFTER BIOS
	 DW	TPALEN			;AND GOES UP TO 01FFFH
;
;	--- DISK DEFINITIONS TABLE ---
;
;	        DISKS 6
DPHDR	EQU	$		;BASE OF DISK PARAMETER BLOCKS
DPE0	DW	0000,0000H	;TRANSLATE TABLE (NONE FOR HARD DISK)
	DW	0000H,0000H	;SCRATCH AREA
	DW	DIRBUF,DPB0	;DIR BUFF, PARM BLOCK
	DW	CSV0,ALV0	;CHECK, ALLOC VECTORS
DPE1	DW	XLT1,0000H	;TRANSLATE TABLE (SD FLOPPY)
	DW	0000H,0000H	;SCRATCH AREA
	DW	DIRBUF,DPB1	;DIR BUFF, PARM BLOCK
	DW	CSV1,ALV1	;CHECK, ALLOC VECTORS
DPE2	DW	XLT2,0000H	;TRANSLATE TABLE (SD FLOPPY)
	DW	0000H,0000H	;SCRATCH AREA
	DW	DIRBUF,DPB2	;DIR BUFF, PARM BLOCK
	DW	CSV2,ALV2	;CHECK, ALLOC VECTORS
DPE3	DW	0000,0000H	;TRANSLATE TABLE (DD FLOPPY)
	DW	0000H,0000H	;SCRATCH AREA
	DW	DIRBUF,DPB3	;DIR BUFF, PARM BLOCK
	DW	CSV3,ALV3	;CHECK, ALLOC VECTORS
DPE4	DW	0000,0000H	;TRANSLATE TABLE  (DD FLOPPY)
	DW	0000H,0000H	;SCRATCH AREA
	DW	DIRBUF,DPB4	;DIR BUFF, PARM BLOCK
	DW	CSV4,ALV4	;CHECK, ALLOC VECTORS
DPE12	DW	0000,0000H	;TRANSLATE TABLE (NOT USED FOR RAMDISK)
	DW	0000,0000H	;SCRATCH AREA
	DW	DIRBUF,MD@DPB	;DIR BUFFER PARM BLOCK
	DW	CSV12,ALV12	;CHECK, ALLOC VECTORS FOR RAMDISK
;
;
;	        DISKDEF 0,0,63,0,2048,3992,1024,0,2
;
DPB0	EQU	OFFSET $	;DISK PARAMETER BLOCK
	DW	64		;SECTORS PER TRACK
	DB	4		;BLOCK SHIFT
	DB	15		;BLOCK MASK
	DB	0		;EXTNT MASK
	DW	3991		;DISK SIZE - 1(1000-2tracks x 4blks/track -1)
	DW	1023		;DIRECTORY MAX
	DB	255		;ALLOC0
	DB	255		;ALLOC1
	DW	0		;CHECK SIZE
	DW	2		;OFFSET
;
;        DISKDEF 1,1,26,6,1024,243,64,64,2
;
DPB1	EQU	OFFSET $	;DISK PARAMETER BLOCK
	DW	26		;SECTORS PER TRACK
	DB	3		;BLOCK SHIFT
	DB	7		;BLOCK MASK
	DB	0		;EXTNT MASK
	DW	242		;DISK SIZE - 1 (75tracks x 3.25bkks/trk -1)
	DW	63		;DIRECTORY MAX
	DB	192		;ALLOC0
	DB	0		;ALLOC1
	DW	16		;CHECK SIZE
	DW	2		;OFFSET
XLT1	EQU	OFFSET $	;TRANSLATE TABLE
	DB	1,7,13,19
	DB	25,5,11,17
	DB	23,3,9,15
	DB	21,2,8,14
	DB	20,26,6,12
	DB	18,24,4,10
	DB	16,22
;
;	        DISKDEF 2,1
;
DPB2	EQU	DPB1		;EQUIVALENT PARAMETERS
XLT2	EQU	XLT1		;SAME TRANSLATE TABLE
;
;	        DISKDEF 3,1,50,0,2048,234,64,64,2
;
DPB3	EQU	OFFSET $	;DISK PARAMETER BLOCK
	DW	50		;SECTORS PER TRACK
	DB	4		;BLOCK SHIFT
	DB	15		;BLOCK MASK
	DB	1		;EXTNT MASK
	DW	233		;DISK SIZE - 1
	DW	63		;DIRECTORY MAX
	DB	128		;ALLOC0
	DB	0		;ALLOC1
	DW	16		;CHECK SIZE
	DW	2		;OFFSET
;
;
;	        DISKDEF 4,3
;
DPB4	EQU	DPB3		;EQUIVALENT PARAMETERS
;
;	        DISKDEF 12,1,480,1,2048,960,128,128,0
;
MD@DPB	equ	offset $	;Disk Parameter Block
	dw	480		;Sectors Per Track
	db	4		;Block Shift
	db	15		;Block Mask
DPB_EXM	RS	1		;Extnt Mask
DPB_DSM	RS	2		;Disk Size - 1 (WHEN FULL RAM 959)
	dw	127		;Directory Max
	db	192		;Alloc0
	db	0		;Alloc1
	dw	32		;Check Size
	dw	0		;Offset
;
;	Uninitialized Scratch Memory Follows:
;
;
FLAGS	RS	1			;BIT FLAGS
					;BIT 0 SET FOR READ OPERATION
					;BIT 1 SET FOR READ IN PROGRESS
					;BIT 2 SET FOR WRITE IN PROGRESS
;
RRTRK	RS	2			;CP/M REQUESTED TRACK ADDRESS
RRDSK	RS	1			;CP/M REQUESTED DRIVE #
RRSEC	RS	2			;CP/M REQUESTED SECTOR
;
URTRK	RS	2			;UNALLOCATED TRACK ADDRESS
URDSK	RS	1			;   DRIVE #
URSEC	RS	1			;   SECTOR ADDRESS
URCNT	RS	1			;   RECORD COUNT
;
HHTRK	RS	2			;HOST (SCRIBE & SHUGART) TRACK ADDRESS
HHDSK	RS	1			;   DRIVE #
HHSEC	RS	1			;   SECTOR ADDRESS
;
RCA	RS	2			;REAL TRACK ADDRESS
RHD	RS	1			;  HEAD
RSA	RS	1			;  SECTOR
;
RETRY	RS	1			;RETRY COUNT
CTA	RS	2			;COMMAND TABLE ADDRESS
ERFLG	RS	1			;ERROR FLAG
DMADR	RS	2			;BUFFER (DMA) ADDRESS
WRTMODE	RS	1			;WRITE MODE
SKRTC	RS	1			;SEEK RETRY COUNT
VSRTC	RS	1			;SEEK VEREFY RETRY COUNT
SKDIR	RS	1			;SEEK DIRECTION
RSKNT	RS	2			;RESIDUAL SEEK COUNT
TEMP	RS	2			;TEMPORARY STORAGE
IOBYT   RS	1			;STORAGE FOR IOBYTE
DMASEG	RS	2			;STORAGE FOR CURRENT SEGMENT ADDRESS
;---
UNIT	RS	1			;STORE FOR FLOPPY NEW UNIT BYTE
ERMASK	RS	1			;FLOPPY ERROR MASK
ERSTAT	RS	1			;STORE OF ERROR FLAG
CMDSV	RS	1			;FLOPPY COMMAND STORE
SPSV	RS	2			;SP SAVE
TEMP2	RS	2			;
COUNT	RS	1			;SECTORS/TRACK SORE
UNITCK	RS	1			;OLD FLOPPY STORE BYTE
RSEEK	RS	1			;NBR OF RESEEKS
RTRY	RS	1			;NBR OF RTRYS
ADRIVE	RS	1			;STORE OF A: TYPE
BDRIVE	RS	1			;STORE OF B: TYPE
MDINIT	RS	1			;FLAG FOR MDISK INITILIZATION
IDSV	RS	6			;STORE FOR TRACK ID DETREMINATION
SPARE	RS	2
;
FLGSIZ	EQU	(OFFSET $)-(OFFSET FLAGS)   ;DEFINES SIZE OF VARIABLE STORAGE
;
LOC_STK	RW	64			;LOCAL STACK FOR INITILIZATION
STKBASE	EQU	OFFSET $
;
;
;	UNINITIALIZED SCRATCH MEMORY FOLLOWS:
;
BEGDAT	EQU	OFFSET $	;START OF SCRATCH AREA
DIRBUF	RS	128		;DIRECTORY BUFFER
ALV0	RS	500		;ALLOC VECTOR
CSV0	RS	0		;CHECK VECTOR
ALV1	RS	31		;ALLOC VECTOR
CSV1	RS	16		;CHECK VECTOR
ALV2	RS	31		;ALLOC VECTOR
CSV2	RS	16		;CHECK VECTOR
ALV3	RS	30		;ALLOC VECTOR
CSV3	RS	16		;CHECK VECTOR
ALV4	RS	30		;ALLOC VECTOR
CSV4	RS	16		;CHECK VECTOR
alv12	rs	120		;Alloc Vector
csv12	rs	32		;Check Vector
ENDDAT	EQU	OFFSET $	;END OF SCRATCH AREA
DATSIZ	EQU	OFFSET $-BEGDAT	;SIZE OF SCRATCH AREA
	DB	0		;MARKS END OF MODULE
;
;
XLAST	EQU	OFFSET $
;
TPASEG	EQU	(XLAST + 0400H+15)/16	;
TPALEN  EQU	01FFFH - TPASEG		;<---- TOP PARAGRAPH OF RAM FOR CP/M
	DB	0			;FOR GENCMD
;
;	----- LOW MEMORY -------

	DSEG	0H
	ORG	0H			;AT LOW MEMORY
;
INT0_OFFSET	RW	1
INT0_SEGMENT	RW	1
					;PAD TO OVERFLOW TRAP VECTOR
		RW	6
INT4_OFFSET	RW	1
INT4_SEGMENT	RW	1
					;PAD TO SYSTEM CALL VECTOR
;
	ORG	380H
;
BDOS_OFFSET	RW	1
BDOS_SEGMENT	RW	1
;
END
